package net.lab1024.sa.admin.module.crawler.service;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.crawler.domain.entity.ShopCopyHisEntity;
import net.lab1024.sa.admin.module.crawler.domain.entity.ShopEntity;
import net.lab1024.sa.admin.module.crawler.domain.form.ShopCopyTaskForm;
import net.lab1024.sa.admin.module.crawler.domain.form.ShopItemForm;
import net.lab1024.sa.admin.module.crawler.domain.form.ShopItemSkuForm;
import net.lab1024.sa.admin.module.crawler.domain.form.ShopTagForm;
import net.lab1024.sa.admin.module.crawler.domain.jddj.JdItemDto;
import net.lab1024.sa.admin.module.crawler.domain.jddj.JdSkusDto;
import net.lab1024.sa.admin.module.crawler.manager.ShopCopyHisManager;
import net.lab1024.sa.admin.module.crawler.manager.ShopManager;
import net.lab1024.sa.base.common.exception.BusinessException;
import net.lab1024.sa.base.common.util.SmartStringUtil;
import net.lab1024.sa.base.constant.RedisKeyConst;
import net.lab1024.sa.base.constant.TpTypeConst;
import net.lab1024.sa.base.module.support.minio.MinioService;
import net.lab1024.sa.base.module.support.redis.RedisService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component
public class ShopCopyTaskService {
    @Autowired
    TpUtilService tpUtilService;
    @Autowired
    ShopManager shopManager;
    @Autowired
    ShopCopyHisManager shopCopyHisManager;
    @Autowired
    MinioService minioService;

    @Autowired
    RedisService redisService;

    // @Async
    public Future<String> copyFactory(ShopCopyTaskForm form) {
        String shopItemStr = form.getShopItemStr();
        String tagStr = form.getTagStr();
        //老店分类
        List<ShopTagForm> oldShopTag = JSONArray.parseArray(SmartStringUtil.filterEmoji(tagStr), ShopTagForm.class);
        //Integer productCount=oldShopTag.stream().mapToInt(ShopTagForm::getProductCount).sum();
        Long tId = form.getTid();
        Long sId = form.getSid();
        //老店
        ShopEntity oldShop = shopManager.getById(sId);
        //新店
        ShopEntity newShop = shopManager.getById(tId);

        //查询复制记录是不是存在
        ShopCopyHisEntity his = shopCopyHisManager.getOne(new QueryWrapper<ShopCopyHisEntity>()
                .eq("sshop_id", oldShop.getShopId())
                .eq("tshop_id", newShop.getShopId())
                .orderByDesc("create_time")
                .last("limit 1")
        );
        List<ShopItemForm> shopItemList = JSONArray.parseArray(shopItemStr, ShopItemForm.class);
        String hisId;
        String taskType="runall";
        if (his != null) {
            hisId = his.getId();
            redisService.set(RedisKeyConst.Support.SUCC_ITEM_COUNT + newShop.getShopId(), his.getSuccItem());
            redisService.set(RedisKeyConst.Support.FAIL_ITEM_COUNT + newShop.getShopId(), 0);
            taskType="error";
        } else {
            hisId = (oldShop.getTp().equals(TpTypeConst.MTCY) ? "M" : "E") + IdUtil.getSnowflakeNextId();
            redisService.set(RedisKeyConst.Support.SUCC_ITEM_COUNT + newShop.getShopId(), 0);
            redisService.set(RedisKeyConst.Support.FAIL_ITEM_COUNT + newShop.getShopId(), 0);
            //初始化复制记录
            his = ShopCopyHisEntity.builder()
                    .id(hisId)
                    .userId(newShop.getUserId())
                    .sId(sId)
                    .sshopId(oldShop.getShopId())
                    .sshopName(oldShop.getShopName())
                    .tId(tId)
                    .tshopId(newShop.getShopId())
                    .tshopName(newShop.getShopName())
                    .totalItem(shopItemList.size())
                    .succItem(0)
                    // .shopDataPath(dataPath)
                    .status(0)
                    .build();
            shopCopyHisManager.save(his);
        }
        //日志门店字符串
        String logShopStr = hisId + "_" + oldShop.getShopId() + "->" + newShop.getShopId();
        //获取老店分类对应新店分类
        Map<String, ShopTagForm> old2newShopTagMap;
        try {
            old2newShopTagMap = createShoptag(oldShopTag, newShop.getCookiestr());
        } catch (Exception e) {
            e.printStackTrace();
            if (his != null) {
                String remark = his.getRemark();
                if (StringUtils.isBlank(remark)) {
                    remark = "";
                } else {
                    remark += "</br>";
                }
                remark += LocalDateTime.now() + ":" + e.getMessage();
                his.setRemark(remark);
                shopCopyHisManager.updateById(his);
            }
            return new AsyncResult<String>(e.getMessage());
        }
        List<ShopItemForm> newShopItemList ;
        if(taskType.equals("runall")){
            newShopItemList=shopItemList;
        }else{
            newShopItemList= shopItemList.stream().filter(item -> StringUtils.isNotBlank(item.getErrorMsg())).collect(Collectors.toList());
        }
        //item分组
        List<List<ShopItemForm>> shopItemGroupList = Lists.partition(newShopItemList, 10);
        //准备开始复制了
        ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 6, 30, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(shopItemGroupList.size()),
                new CustomizableThreadFactory("U" + newShop.getUserId() + "_" + logShopStr + "-"),
                new ThreadPoolExecutor.AbortPolicy()
        );
        List<String> waimaiRandomCategory = tpUtilService.getWaimaiRandomCategory(newShop.getCookiestr());
        List<CompletableFuture<String>> tasks = new ArrayList<>();
        //京东内容初步整理完成。接下去思路 如果商品数据出错了直接在原来商品数据设置errorMsg.然后再存入数据库。。。默认所有分类，数据多上传。
        // 活动数据 去sku那边判断是否有actPrice.新店铺活动需要的的数据也直接存进到文本。不依赖redis了
        for (List<ShopItemForm> shopItemFormList : shopItemGroupList) {
            CompletableFuture<String> task = CompletableFuture.supplyAsync(() -> {
                for (ShopItemForm shopItemForm : shopItemFormList) {
                    String errMessage = "成功";
                    Integer fixedStatus = null;
                    try {
                        JdItemDto jdItem = tpUtilService.getJdItem(newShop.getCookiestr(), shopItemForm, old2newShopTagMap, waimaiRandomCategory);
                        fixedStatus = jdItem.getFixedStatus();
                        //临时注销掉
                        //JSONObject saveResultObj = tpUtilService.saveSpuProductInfo(newShop.getCookiestr(), jdItem);
                        //errMessage = saveResultObj.getString("msg");
                    } catch (Exception e) {
                        errMessage = e.getMessage();
                    }
                    if (!"成功".equals(errMessage)) {
                        if (StringUtils.isNoneBlank(hisId)) {
                            redisService.increment(RedisKeyConst.Support.FAIL_ITEM_COUNT + hisId);
                        }
                        shopItemForm.setErrorMsg(errMessage);
                    } else {
                        shopItemForm.setErrorMsg(null);
                        if (StringUtils.isNoneBlank(hisId)) {
                            redisService.increment(RedisKeyConst.Support.SUCC_ITEM_COUNT + hisId);
                        }
                        try {
                            //修改库存
                            JSONArray skuQuery = tpUtilService.skuQuery(newShop.getCookiestr(), shopItemForm.getName());
                            if (!CollectionUtils.isEmpty(skuQuery)) {
                                List<JdSkusDto> skuList = skuQuery.toList(JdSkusDto.class);
                                Map<String, JdSkusDto> jdSkuMap = new HashMap<>();
                                skuList.forEach(sku -> {
                                    jdSkuMap.put(sku.getOutSkuId(), sku);
                                });
                                List<ShopItemSkuForm> skus = shopItemForm.getSkus();
                                skus.forEach(sku -> {
                                    JdSkusDto jdSkusDto = jdSkuMap.get(sku.getId());
                                    if (jdSkusDto != null) {
                                        //更新库存并保存skuid
                                        sku.setJdSkuId(jdSkusDto.getSkuId());
                                        tpUtilService.updateCurrentQty(newShop.getCookiestr(), jdSkusDto.getSkuId(), newShop.getShopId(), sku.getStock());
                                    }
                                });
                            }
                            //修改上下架状态
                            JSONArray querySpuList = tpUtilService.querySpuList(newShop.getCookiestr(), shopItemForm.getName());
                            if (!org.springframework.util.CollectionUtils.isEmpty(querySpuList)) {
                                if (fixedStatus != null && (fixedStatus == 0 || fixedStatus == 1)) {
                                    tpUtilService.updateWareUpStatus(newShop.getCookiestr(),
                                            Arrays.asList(querySpuList.getJSONObject(0).getJSONObject("ware").getLong(
                                                    "superId")), 1);
                                }
                            }
                        } catch (Exception e) {
                            log.warn("{},更新库存或商品上下架状态出错：{}", logShopStr, e.getCause());
                        }
                    }
                }
                return logShopStr + ",处理完商品数量：" + shopItemFormList.size();
            }, executor);
            tasks.add(task);
        }

        for (int t = 0; t < tasks.size(); t++) {
            tasks.get(t).thenAccept(e -> {
                log.info("执行异步任务结果:{}", e);
            }).exceptionally(e -> {
                log.error("执行异步任务里层报错,{}", e.getCause());
                return null;
            }).exceptionally(e -> {
                e.printStackTrace();
                return null;
            }).join();
        }
        //关闭线程池
        try {
            executor.shutdown();
        } catch (Exception e) {
            log.error("{},关闭线程池错误：{}", hisId, e.getCause());
        }
        //统计多少正确
        long count = shopItemList.stream().filter(item -> StringUtils.isBlank(item.getErrorMsg())).count();
        if (his != null) {
            his.setSuccItem(Integer.parseInt(count + ""));
            his.setStatus(his.getSuccItem().equals(his.getTotalItem()) ? 1 : -2);
            String shopData = JSONObject.toJSONString(form, JSONWriter.Feature.LargeObject);
            String dataPath = minioService.writeData(shopData, hisId, "");
            his.setShopDataPath(dataPath);
            shopCopyHisManager.updateById(his);
        }
        return new AsyncResult<String>("任务提交成功!");
    }

    /**
     * 创建分类
     *
     * @param oldShopTag
     * @param cookiestr
     * @return
     */
    public Map<String, ShopTagForm> createShoptag(List<ShopTagForm> oldShopTag, String cookiestr) {
        List<String> errorMsg = new ArrayList<>();
        List<ShopTagForm> newShopTag = tpUtilService.getshopTags(cookiestr);
        Map<String, ShopTagForm> newShopTagMap = newShopTag.stream().collect(Collectors.toMap(ShopTagForm::getTagName, Function.identity()));
        Map<String, ShopTagForm> old2newShopTagMap = new HashMap<>();
        for (ShopTagForm form : oldShopTag) {
            String oldTagName = form.getTagName();
            ShopTagForm newShopTagForm = newShopTagMap.get(oldTagName);
            if (newShopTagForm == null) {
                try {
                    String newShopTagId = tpUtilService.createShopTag(cookiestr, oldTagName);
                    newShopTagForm = ShopTagForm.builder()
                            .tagId(newShopTagId)
                            .tagName(oldTagName)
                            .build();
                } catch (Exception e) {
                    errorMsg.add(oldTagName + ":" + e.getMessage());
                }
            }
            old2newShopTagMap.put(form.getTagId(), newShopTagForm);
        }
        if (!CollectionUtils.isEmpty(errorMsg)) {
            throw new BusinessException("创建分类失败！：" + String.join("</br>", errorMsg.toString()));
        }
        return old2newShopTagMap;
    }
}